یه تابستون متفاوت با یه تصمیم هوشمندانه! دوره هوش مصنوعی یه تابستون متفاوت با یه تصمیم هوشمندانه! دوره هوش مصنوعی
🎯 ثبت نام
بستن تبلیغات
دوره آموزش جامع PHP از صفر تا صد با پروژه‌های عملی

توی دوره رایگان PHP، هر چیزی که برای حرفه‌ای شدن نیاز داری رو یاد می‌گیری! از مفاهیم پایه تا پیشرفته، همراه با یه پروژه واقعی برای ساخت یه سایت مثل آپارات.

مشاهده بیشتر
دوره پروژه‌محور لاراول: ساخت وبسایت خبری از صفر تا صد

توی این دوره با هم یه وبسایت خبری واقعی رو از صفر می‌سازیم! از طراحی دیتابیس و احراز هویت تا ساخت API و یه پنل مدیریت حرفه‌ای، همه رو یاد می‌گیریم و آماده پروژه‌های واقعی میشی!

مشاهده بیشتر

آموزش رخدادها (event ها) در لاراول

رخدادها (event ها) در لاراول

  1. مقدمه
  2. ثبت event ها / Listener ها
  3. نحوه ی تعریف رخدادها
  4. نحوه ی معرفی Listener ها
    • در صف قرار دادن و زمان بندی Event Listener ها
  5. اعلان event ها با متد fire
  6. ارسال همگانی (Broadcast) رخدادها
    • تنظیمات و کانفیگ
    • علامت گذاری event ها برای ارسال همگانی
    • ارسال همگانی (broadcast) داده ها
    • تنظیمات ارسال همگانی رخدادها
    • استفاده از event broadcast ها
  7. event subscriber ها

مقدمه

رخدادها در Laravel با پیاده سازی الگوی observer این امکان را فراهم می آورد تا برای event های برنامه ی خود subscribe کرده (به آن ها گوش داده) و گوش فراخوان تخصیص دهید. کلاس های Event معمولا در پوشه ی app/Events ذخیره شده در حالی است که گوش فراخوان های آن ها (listener) در دایرکتوری app/Listeners نگه داری می شوند.

ثبت event ها / Listener ها

EventServiceProvider که با لاراول عرضه می شود محلی مناسب برای ثبت تمامی event listener ها فراهم می کند. پراپرتی listen آرایه ای از تمامی event ها (کلیدها) و listener های مربوطه ی آن ها (مقادیر آن ها) را در خود نگه می دارد. می توانید با توجه به نیاز اپلیکیشن خود هر تعداد event که مورد نیاز است به این آرایه اضافه نمایید. در زیر یک رخداد به نام PodcastWasPurchased به آرایه ی مزبور اضافه می کنیم:

1
2
3
4
5
6
7
8
9
10
11
/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
   'App\Events\PodcastWasPurchased' => [
       'App\Listeners\EmailPurchaseConfirmation',
   ],
];
<button></button>

نحوه ی ایجاد کلاس های event / listener

طبیعتا فرایند ایجاد فایل ویژه ی هر event و listener خسته کننده می باشد. بجای این روش ملال آور می توانید listener ها و event های مورد نیاز برنامه ی خود را در EventServiceProvider درج نموده و بعد دستور ساده ی event:generate را اجرا کنید. دستور ذکر شده تمامیevent ها و listener های لیست شده در EventServiceProvider را تولید می کند. آن دسته از event ها و listener هایی که از قبل موجود هستند نیز ثابت و بدون تغییر باقی خواهند ماند:

1
2
                    php artisan event:generate
<button></button>

ثبت event ها به روش دستی

در لاراول event ها به طور معمول داخل متغیر آرایه ای $listen مقیم در EventServiceProvider ثبت شوند. با این حال می توانید رخدادها را با بهره گیری از یک event dispatcher (ارسال کننده ی رخداد) از طریق فاساد Event و یا پیاده سازی (implementation) کانترکتIlluminate\Contracts\Events\Dispatcher خود به صورت دستی ثبت نمایید:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * Register any other events for your application.
 *
 * @param \Illuminate\Contracts\Events\Dispatcher $events
 * @return void
 */
public function boot(DispatcherContract $events)
{
   parent::boot($events);
   $events->listen('event.name', function ($foo, $bar) {
       //
   });
}
<button></button>

ثبت listener ها از طریق پارامتر * (wildcard)

همچنین می توانید event listener را با ارسال * به عنوان پارامتر wildcard به گونه ای ثبت نمایید که قادر باشد چندین رخداد را یکجا گرفته و به آن ها گوش فرا دهد. listener هایی که با * ثبت شده باشند این قابلیت را دارند تا تمامی داده های آرایه را در قالب یک آرگومان واحد دریافت کنند:

1
2
3
4
$events->listen('event.*', function (array $data) {
   //
});
<button></button>

نحوه ی تعریف Event ها

کلاس event صرفا یک ظرف برای ذخیره ی اطلاعات مربوط به رخدادهای برنامه می باشد. برای مثال تصور کنید رخداد PodcastWasPurchasedای که خود تعریف کرده ایم یک شی Eloquent دریافت می کند:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
namespace App\Events;
use App\Podcast;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class PodcastWasPurchased extends Event
{
   use SerializesModels;
   public $podcast;
   /**
    * Create a new event instance.
    *
    * @param Podcast $podcast
    * @return void
    */
   public function __construct(Podcast $podcast)
   {
       $this->podcast = $podcast;
   }
}
<button></button>

همان طور که از مثال فوق مشاهده می شود، این کلاس event هیچ منطق خاصی را دربرنمی گیرد. بلکه صرفا یک ظرف برای نگهداری اطلاعات شیPodcast خریداری شده می باشد. چنانچه شی event توسط تابع serialize زبان PHP سریال شده باشد، در آن صورت تریتSerializesModels (که event داخل کلاس از آن استفاده می کند) تمامی مدل های Eloquent را به صورت سریال در می آورد.

نحوه ی تعریف Listener ها

در گام بعدی نگاه مختصری به listener یا گوش فراخوان event نمونه ی خود می اندازیم. Event listener ها نمونه ی event را در متد handleخود دریافت می کنند. دستور event:generate به صورت خودکار کلاس event مربوطه را وارد (import) نموده و event مورد نظر را در متدhandle اعلان-نوع (type-hint) می کند. داخل بدنه ی متد handle می توانید منطق لازم برای پاسخ دهی به آن رخداد را پیاده سازی و اجرا کنید.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
namespace App\Listeners;
use App\Events\PodcastWasPurchased;
class EmailPurchaseConfirmation
{
   /**
    * Create the event listener.
    *
    * @return void
    */
   public function __construct()
   {
       //
   }
   /**
    * Handle the event.
    *
    * @param PodcastWasPurchased $event
    * @return void
    */
   public function handle(PodcastWasPurchased $event)
   {
       // Access the podcast using $event->podcast...
   }
}
<button></button>

Event listener ها همچنین می توانند dependency های مورد نیاز خود را در توابع constructor اعلان-نوع (type-hint) کنند. از آنجایی که تمامی event-listener ها توسط service container در دسترس قرار می گیرند (resolve می شوند) dependency ها نیز متعاقبا به صورت اتوماتیک به داخل کلاس تزریق می شوند:

1
2
3
4
5
6
use Illuminate\Contracts\Mail\Mailer;
public function __construct(Mailer $mailer)
{
   $this->mailer = $mailer;
}
<button></button>

جلوگیری از انتشار و گسترش (propagation) یک رخداد

گاهی لازم می شود از پخش یک رخداد به دیگر listener ها جلوگیری نمایید. برای این منظور کافی است مقدار false را از متد handle گوش فراخوان (listener) خود بازگردانی نمایید.

در صف قرار دادن و زمان بندی Event Listener ها

می توانید event listener های خود را داخل صف قرار داده و بدین وسیله اجرای آن ها را زمان بندی نمایید. برای این منظور تنها بایستی اینترفیسShouldQueue را به کلاس Listener اضافه کنید. Listener هایی که با اجرای دستور آرتیزان event:generate تولید شده اند، همگی از قبل این interface را داخل namespace جاری به صورت import شده دارند. از اینرو می توانید به سرعت از آن ها استفاده نمایید:

1
2
3
4
5
6
7
8
9
<?php
namespace App\Listeners;
use App\Events\PodcastWasPurchased;
use Illuminate\Contracts\Queue\ShouldQueue;
class EmailPurchaseConfirmation implements ShouldQueue
{
   //
}
<button></button>

حال زمانی که listener برای یک event صدا خورده می شود، توسط event dispatcher و از طریق سیستم queue (زمان بندی) لاراول به صورت خودکار در صف قرار می گیرد. چنانچه به هنگام اجرای Listener (توسط سیستم queue) هیچ خطایی رخ ندهد، آنگاه عملیات در صف قرار گرفته (queued job) پس از اتمام پردازش به صورت اتوماتیک حذف می شود.

دسترسی به Queue به روش دستی

در صورت نیاز می توانید به متدهای delete و release عملیات در صف قرار گرفته (queue job) دسترسی داشته باشید. مشخصه (trait)Illuminate\Queue\InteractsWithQueue که به صورت پیش فرض برای تمامی listener های ایجاد شده import می شود، دسترسی به این توابع را برای شما امکان پذیر می سازد:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
namespace App\Listeners;
use App\Events\PodcastWasPurchased;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class EmailPurchaseConfirmation implements ShouldQueue
{
   use InteractsWithQueue;
   public function handle(PodcastWasPurchased $event)
   {
       if (true) {
           $this->release(30);
       }
   }
}
<button></button>

اعلان Event ها با متد fire

به منظور راه اندازی (fire) رخدادها می توانید از فاساد Event بهره بگیرید. کافی است نمونه ای از event را به متد fire ارسال نمایید. متد مذکورevent مورد نظر را به تمامی listener هایی که برای آن ثبت شده اند (و به آن گوش فرا می دهند)، ارسال می کند:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
namespace App\Http\Controllers;
use Event;
use App\Podcast;
use App\Events\PodcastWasPurchased;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
   /**
    * Show the profile for the given user.
    *
    * @param int $userId
    * @param int $podcastId
    * @return Response
    */
   public function purchasePodcast($userId, $podcastId)
   {
       $podcast = Podcast::findOrFail($podcastId);
       // Purchase podcast logic...
       Event::fire(new PodcastWasPurchased($podcast));
   }
}
<button></button>

این کار را می توانید با فراخوانی تابع کمکی event نیز انجام دهید:

1
2
                    event(new PodcastWasPurchased($podcast));
<button></button>

ارسال همگانی (Broadcast) Event ها

بیشتر برنامه های تحت وب امروزه از web socket ها برای پیاده سازی رابط های کاربری بلادرنگ (real-time) ،با قابلیت بروز رسانی پویا (live-updating) بهره می گیرند. زمانی که بخشی از داده ها در سمت سرویس گیرنده (server) بروز آوری می شوند، بی درنگ یک پیغام از طریقconnection websocket (اتصال ماندگار دو طرفه ای که وب سوکت برقرار می کند) به سرویس گیرنده ارسال شده و توسط client مدیریت می شود.
لاراول برای کمک به ساخت این دست از اپلیکیشن های تحت وب، به شما اجازه می دهد تا رخدادهای خود را از طریق websocket connection به طور همگانی ارسال (broadcast) نمایید. ارسال همگانی رخدادها نیز این امکان را فراهم می کند تا اسامی رخدادها را بین کد سمت سرور و کد جاوا اسکریپت (client-side JavaScript framework) در سمت کلاینت به اشتراک بگذارید (رخدادها در هر دو طرف به یک اسم شناخته شوند).

تنظیمات و کانفیگ

تمامی گزینه و آپشن های تنظیم مربوط به پخش همگانی رخدادها (event broadcast) داخل فایل کانفیگ config/broadcasting.php ذخیره می شوند. لاراول به صورت پیش فرض از درایورهای ارسال همگانی (broadcast driver) متعددی پشتیبانی می کند. از جمله می توان به درایورPusher، Redis و یک log ویژه ی توسعه ی local برنامه و عیب یابی آن اشاره کرد. برای هر یک از این درایورها یک نمونه configuration لحاظ شده است.

Dependency ها و پیش نیاز های ارسال همگانی رخدادها (event broadcasting)

برای پخش همگانی رخدادها (event broadcasting) به پکیج های زیر نیاز خواهید داشت:

  • Pusher: pusher/pusher-php-server ~2.0
  • Redis: predis/predis ~1.0

پیش نیازهای Queue

پیش از broadcast و اقدام به پخش همگانی رخدادها بایستی یک queue listener تنظیم و راه اندازی نمایید. تمامی عملیات مربوط به پخش همگانی رخدادها یا به اصطلاح event broadcastingاز طریق عملیات زمانبندی شده و queued job ها مدیریت می شوند. بنابراین می توان گفت که زمان پاسخ دهی (response time) برنامه ی شما به طور قابل توجهی تحت تاثیر قرار نمی گیرد.

علامت گذاری event ها برای ارسال همگانی

با پیاده سازی اینترفیس Illuminate\Contracts\Broadcasting\ShouldBroadcast در کلاس event مربوطه می توان به لاراول اعلان کرد که کدام رخدادها بایستی به صورت همگانی پخش (broadcast) شوند. interface مزبور ایجاب می کند ما یک متد به نام ShouldBroadcast را پیاده سازی کنیم. این متد باید آرایه ای از اسامی cahnnel ها را که event مورد نظر باید بر روی آن broadcast شود را در خروجی برگرداند:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
namespace App\Events;
use App\User;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ServerCreated extends Event implements ShouldBroadcast
{
 use SerializesModels;
   public $user;
   /**
    * Create a new event instance.
    *
    * @return void
    */
   public function __construct(User $user)
   {
       $this->user = $user;
   }
   /**
    * Get the channels the event should be broadcast on.
    *
    * @return array
    */
   public function broadcastOn()
   {
       return ['user.'.$this->user->id];
   }
}
<button></button>

پس از آن کافی است event را به روش معمول اعلان (fire) کنید. پس از اعلان event، queued job به صورت خودکار رخداد را از طریق درایورbroadcast مشخص شده به صورت همگانی ارسال می کند.

پخش همگانی داده ها (Broadcast Data)

با ارسال (broadcast) یک رخداد، تمامی پراپرتی های public آن نیز به صورت خودکار سریال (serialize) شده و به عنوان payload (اطلاعات همراه) آن رخداد ارسال می شوند. این کار زمینه ی دسترسی به تمامی داده های public رخداد را از طریق اپلیکیشن جاوا اسکریپت مهیا می کند. بنابراین اگر رخداد مورد نظر تنها یک property با سطح دسترسی public به نام$user داشته باشد و آن متغیر حاوی یک مدل Eloquent باشد، در آن صورت payload ای که همراه این رخداد ارسال می شود (broadcast payload)، به صورت زیر خواهد بود:

1
2
3
4
5
6
7
8
{
   "user": {
       "id": 1,
       "name": "Jonathan Banks"
       ...
   }
}
<button></button>

اگر می خواهید بر روی payload خود کنترل fine-grained تر (مستقل تر و دقیق تری بر اجزا) داشته باشید، در آن صورت توصیه می کنیم یک متدbroadcastWith نیز به رخداد خود اضافه نمایید. این متد داده هایی را که می خواهید همراه با رخداد مورد نظر broadcast شوند را در قالب یک آرایه در خروجی برمی گرداند:

1
2
3
4
5
6
7
8
9
10
/**
 * Get the data to broadcast.
 *
 * @return array
 */
public function broadcastWith()
{
   return ['user' => $this->user->id];
}
<button></button>

تنظیمات سفارشی event broadcasting

تنظیم اسم event

به صورت پیش فرض، اسم رخداد همان اسم کامل کلاسی می باشد که اطلاعات event در آن ریخته شده است. چنانچه اسم کلاس event مورد نظر، به عنوان مثال، App\Events\ServerCreated باشد در آن صورت اسم broadcast event نیز App\Events\ServerCreated خواهد بود. می توانید اسم event را با فراخوانی متد broadcastAs در کلاس event به صورت زیر تنظیم نمایید:

1
2
3
4
5
6
7
8
9
10
/**
 * Get the broadcast event name.
 *
 * @return string
 */
public function broadcastAs()
{
   return 'app.server-created';
}
<button></button>

تنظیم اختصاصی Queue و رخدادهای در صف قرار گرفته

به صورت پیش فرض، هر رخدادی که قرار است اعلان همگانی شود ( برای queue connection پیش فرض) داخل queue (صف) از پیش تعیین شده ی خود در فایل تنظیماتqueue.php قرار می گیرد. می توانید queue مورد استفاده ی اعلان کننده ی رخداد (event broadcaster) را با افزودن و فراخونی متد onQueue در کلاس event، سفارشی تنظیم نمایید. این متد اسم queue دلخواه (که قصد استفاده از آن را دارید) را به عنوان خروجی برمی گرداند:

1
2
3
4
5
6
7
8
9
10
/**
 * Set the name of the queue the event should be placed on.
 *
 * @return string
 */
public function onQueue()
{
   return 'your-queue-name';
}
<button></button>

استفاده (consume) از Event Broadcast ها

Pusher

می توانید با استفاده از درایور pusher (و استفاده از جعبه توسعه نرم افزار/SDK Pusher جاوا اسکریپت) از رخدادهای اعلان همگانی شده ها استفاده کنید (در اصطلاح لاراول آن ها را consume کنید). در زیر با استفاده از درایور Pusher، از رخدادApp\Events\ServerCreated که در مثال های قبلی با آن برخورد داشتیم استفاده می کنیم:

1
2
3
4
5
6
this.pusher = new Pusher('pusher-key');
this.pusherChannel = this.pusher.subscribe('user.' + USER_ID);
this.pusherChannel.bind('App\\Events\\ServerCreated', function(message) {
   console.log(message.user);
});
<button></button>

Redis

در صورت استفاده از Redis، بایستی Redis pub/sub consumer اختصاصی خود (pub/sub = سیستم ارسال/دریافت پیام) را برای دریافت پیغام ها نوشته و سپس آن ها (پیغام ها) را از طریق تکنولوژی websocket دلخواه خود به طور همگانی ارسال نمایید. به عنوان مثال، می توانید از کتابخانه ی پرطرفدار Socket.io که داخل Node (مخزن آنلاین ماژول ها) در دسترس می باشد، استفاده نمایید.
می توانید با بهره گیری از کتابخانه هایsocket.io و ioredis موجود در Node، در کم ترین زمان یک event broadcaster بنویسید تا تمامی رخدادهایی که توسط اپلیکیشن به صورت همگانی اعلان (broadcast) می شود را ارسال (publish) نمایید.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var app = require('http').createServer(handler);
var io = require('socket.io')(app);
var Redis = require('ioredis');
var redis = new Redis();
app.listen(6001, function() {
   console.log('Server is running!');
});
function handler(req, res) {
   res.writeHead(200);
   res.end('');
}
io.on('connection', function(socket) {
   //
});
redis.psubscribe('*', function(err, count) {
   //
});
redis.on('pmessage', function(subscribed, channel, message) {
   message = JSON.parse(message);
   io.emit(channel + ':' + message.event, message.data);
});
<button></button>

Event Subscriber ها (کلاس گوش دهنده به رخدادها)

Event subscriber ها کلاس هایی هستند که می توانند همزمان به چندین رخداد از داخل خود کلاس گوش فرا داده (به اصطلاح subscribe کرده) و بدین وسیله این امکان را به شما بدهند تا چندین event handler داخل یک کلاس واحد تعریف نمایید. subscriber ها باید یک متد subscribeتعریف کنند. به عنوان آرگومان نیز یک نمونه از event dispatcher به متد ذکر شده پاس داده می شود:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
namespace App\Listeners;
class UserEventListener
{
   /**
    * Handle user login events.
    */
   public function onUserLogin($event) {}
   /**
    * Handle user logout events.
    */
   public function onUserLogout($event) {}
   /**
    * Register the listeners for the subscriber.
    *
    * @param Illuminate\Events\Dispatcher $events
    */
   public function subscribe($events)
   {
       $events->listen(
           'App\Events\UserLoggedIn',
           'App\Listeners\UserEventListener@onUserLogin'
       );
       $events->listen(
           'App\Events\UserLoggedOut',
           'App\Listeners\UserEventListener@onUserLogout'
       );
   }
}
<button></button>

ثبت event subscriber

پس از تعریف subscriber، بایستی آن را در Event Subscriber ثبت کنید. می توانید subscriber ها را در متغیر $subscribe داخل کلاسEventServiceProvider ثبت نمایید. در مثال زیر subscriber ای به نام UserEventListener را داخل property مزبور اضافه می کنیم:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
   /**
    * The event listener mappings for the application.
    *
    * @var array
    */
   protected $listen = [
       //
   ];
   /**
    * The subscriber classes to register.
    *
    * @var array
    */
   protected $subscribe = [
       'App\Listeners\UserEventListener',
   ];
}
<button></button>
1395/03/07 8372 1630
رمز عبور : tahlildadeh.com یا www.tahlildadeh.com
نظرات شما

نظرات خود را ثبت کنید...






آموزش برنامه نویسی کاربر میهمان 1396/04/06
hb

عالی بود ایول